package cz.czu.pef.DataModelling;

import java.util.*;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;
import javax.persistence.*;

import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import cz.czu.pef.DataModelling.utils.Lazy;

@Entity
@Table(name="EMPLOYEES")
@Inheritance(strategy=InheritanceType.JOINED)
@NamedQueries({
	@NamedQuery(name="SortedEmployees", query="select e.person.firstName, e.person.lastName, e.person.birthDate from cz.czu.pef.DataModelling.Employee e order by e.person.birthDate asc, e.person.lastName asc, e.person.firstName asc"),
	@NamedQuery(name="findEmployeeByName", query="SELECT e FROM Employee e WHERE e.person.firstName = :firstName AND e.person.lastName = :lastName")
	})
//@DiscriminatorValue("EMPLOYEE")
//@DiscriminatorColumn(name="subclass", discriminatorType=DiscriminatorType.CHAR)
@ManagedBean
@ViewScoped
@Component
public class Employee extends IdPersistenceObject
{
	private static final long serialVersionUID = -3272793380650077540L;

	@ManyToMany(fetch=FetchType.LAZY, targetEntity=Company.class, mappedBy="employees") // no cascade!
	private List<Company> employers;

	@ManyToOne(fetch=FetchType.EAGER, cascade={CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REFRESH})
	private Person person;

	@ManyToMany(fetch = FetchType.LAZY, targetEntity = MedicalExamination.class, cascade={CascadeType.ALL}) // all cascades!
	@JoinTable(name="EMPLOYEES_MEDICAL_EXAMINATIONS")
	private Set<MedicalExamination> medicalExaminations;

	@ManyToMany(fetch = FetchType.LAZY, targetEntity = Role.class, cascade={CascadeType.ALL}) // all cascades!
	@JoinTable(name="EMPLOYEES_ROLES")
	private Set<Role> roles;

	@ManyToMany(fetch = FetchType.LAZY, targetEntity = Training.class, cascade={CascadeType.ALL}) // all cascades!
	@JoinTable(name="EMPLOYEES_TRAININGS")
	private Set<Training> trainings;

	public Employee()
	{
		person = new Person();
	}

	public Employee(Person person)
	{
		this.setPerson(person);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public List<Company> getEmployers()
	{
		return employers;
	}

	public void addEmployer(Company newEmployer)
	{
		if (employers == null)
			employers = new ArrayList<Company>();
		employers.add(newEmployer);
	}

	
	public Person getPerson()
	{
		return person;
	}

	
	public void setPerson(Person person)
	{
		this.person = person;
	}
	
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<MedicalExamination> getMedicalExaminations()
	{
		return medicalExaminations;
	}

	public void addMedicalExamination(MedicalExamination medicalExamination)
	{
		if (medicalExaminations == null)
			medicalExaminations = new HashSet<MedicalExamination>();
		medicalExaminations.add(medicalExamination);
	}

	
	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Role> getRoles()
	{
		return roles;
	}

	public void addRole(Role role)
	{
		if (roles == null)
			roles = new HashSet<Role>();

		roles.add(role);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	public Set<Training> getTrainings()
	{
		return trainings;
	}

	public void addTraining(Training training)
	{
		if (trainings == null)
			trainings = new HashSet<Training>();

		trainings.add(training);
	}

	@Lazy
	@Transactional(readOnly=true, propagation=Propagation.REQUIRED)
	@Override
	public String toString()
	{
		StringBuilder builder = new StringBuilder();
		builder.append("Employee [person=");
		builder.append(person);
		builder.append(", medicalExaminations=");
		builder.append(medicalExaminations);
		builder.append(", roles=");
		builder.append(roles);
		builder.append(", trainings=");
		builder.append(trainings);
		builder.append(", toString()=");
		builder.append(super.toString());
		builder.append("]");
		return builder.toString();
	}
	
	/**
	 * Can be deleted after no employer is referencing it.
	 */
	@Override
	public boolean canBeRemoved()
	{
		return getEmployers().size() == 0;
	}
}